package db

import (
	"database/sql"
	"fmt"
	"yunpan/cache/log"
	mydb "yunpan/db/mysql"
)

type TableFile struct {
	FileHash string
	FileName sql.NullString
	FileSize sql.NullInt64
	FileAddr sql.NullString
}


// ExecResult: sql函数执行的结果
type ExecResult struct {
	Suc  bool        `json:"suc"`
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

func OnFileUploadFinished(filehash , filename, fileaddr string, filesize int64) bool {
	stmt, err := mydb.DBConn().Prepare("insert ignore into tbl_file (`file_sha1`, `file_name`, `file_size`, `file_addr`, `status`) values (?,?,?,?,1)")
	if err != nil {
		fmt.Println("failed to prepare err"+err.Error())
		return false
	}
	defer stmt.Close()
	ret, err := stmt.Exec(filehash, filename, filesize, fileaddr)
	if err != nil {
		fmt.Println("failed exec err"+err.Error())
		return false
	}

	if rf, err := ret.RowsAffected(); err == nil {
		if rf <= 0 {
			fmt.Println("File with hash:%s has been uploaded before", filehash)
		}
		return true
	}
	return false
}


func GetFileMeta(filehash string) (* TableFile, error) {
	stmt, err := mydb.DBConn().Prepare("select file_sha1, file_name, file_size," +
		" file_addr from tbl_file where file_sha1=? and status=1 limit 1")
	if err != nil {
		log.Ob().Warn("failed prepare")
		return nil, err
	}
	defer stmt.Close()

	tfile := TableFile{}
	err = stmt.QueryRow(filehash).Scan(&tfile.FileHash,&tfile.FileName,&tfile.FileSize,&tfile.FileAddr)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		log.Ob().Warn("failed queryrow")
		return nil, err
	}
	return &tfile, nil
}

func IsFileUploaded(filehash string) bool {
	stmt, err := mydb.DBConn().Prepare("select 1 from tbl_file "+
		" where file_sha1=? and status=1 limit 1")
	if err != nil {
		log.Ob().Warn("failed prepare")
		return false
	}
	rows, err := stmt.Query(filehash)
	if err != nil {
		return false
	} else if rows == nil || !rows.Next() {
		return false
	}
	return true
}

func GetFileMetaList(limit int) ([]TableFile, error) {
	stmt, err := mydb.DBConn().Prepare("select file_sha1, file_name, file_size, file_addr "+
		" from tbl_file where status=1 limit ? ")
	if err != nil {
		log.Ob().Warn("failed prepare")
		return nil, err
	}
	defer stmt.Close()
	rows, err := stmt.Query(limit)
	if err != nil {
		log.Ob().Warn("failed query"+err.Error())
		return nil, err
	}
	tfiles := []TableFile{}
	for rows.Next() {
		tfile := TableFile{}
		err = rows.Scan(&tfile.FileHash, &tfile.FileName, &tfile.FileSize, &tfile.FileAddr)
		if err != nil {
			log.Ob().Warn(err.Error())
			break
		}
		tfiles = append(tfiles, tfile)
	}
	return tfiles, nil
}


// UpdateFileLocation : 更新文件的存储地址(如文件被转移了)
func UpdateFileLocation(filehash string, fileaddr string) (res ExecResult) {
	stmt, err := mydb.DBConn().Prepare(
		"update tbl_file set`file_addr`=? where  `file_sha1`=? limit 1")
	if err != nil {
		log.Ob().Warn("预编译sql失败, err:" + err.Error())
		res.Suc = false
		res.Msg = err.Error()
		return
	}
	defer stmt.Close()

	ret, err := stmt.Exec(fileaddr, filehash)
	if err != nil {
		log.Ob().Warn(err.Error())
		res.Suc = false
		res.Msg = err.Error()
		return
	}

	if rf, err := ret.RowsAffected(); nil == err {
		if rf <= 0 {
			log.Ob().Warn("更新文件location失败, filehash:%s", filehash)
			res.Suc = false
			res.Msg = "无记录更新"
			return
		}
		res.Suc = true
		return
	} else {
		res.Suc = false
		res.Msg = err.Error()
		return
	}
}